隨著科技與網路越來越發達,我漸漸減少去網咖的次數,畢竟家裡已經有電腦了,家人為了避免我老是往網咖跑,還特地幫家裡申請了 HiNet 的寬頻服務,讓我能在家上網。
Note
HiNet,全名「中華電信網際網路服務」,是台灣最大的網際網路服務供應商(ISP),提供寬頻上網、光纖等多種網路服務。
當時我最投入的一款遊戲,就是《仙境傳說 Online》。這遊戲我至少玩了超過 10 年,從國小一路玩到出社會,中間甚至還多次回鍋。
為什麼特別提這件事呢?因為我那時候帳號被盜超多次。而且幾乎都是我在遊戲官網輸入帳號密碼、儲值完點數之後。
「X!又被盜了!」我氣得在即時通上抱怨。
「蛤?你又被盜了?你盜之前有做什麼嗎?」網友問我。
「就去官網輸入帳號密碼然後儲值,結果就被盜啦!Why!」我回答。
對,就是滿滿的「Why」。因為我真的不懂為什麼會被盜:我確認過那是官網,不是釣魚網站,電腦也才剛重灌過,不可能中毒。況且如果真的是釣魚網站,點數卡理論上也該一起被盜走,但事實上並沒有。
直到後來,資訊課老師用 Wireshark 示範了如何抓取網路封包,並解釋 HTTP 是一個 完全不安全的協定 。
Note
上圖是『史萊姆第一個家』的網站,由於該網站沒有使用 HTTPS 協定,因此瀏覽器會顯示 「不安全」 的警告訊息。
那一瞬間我才恍然大悟——原來當年我在遊戲官網輸入帳號密碼時,因為官網用的竟然是 HTTP,導致帳密在傳輸途中被攔截了……
HTTP 完整名稱是 HyperText Transfer Protocol,中文翻譯為「超文本傳輸協定」,它是用來在網路上傳輸資料的協定/標準。
當你打開瀏覽器並輸入一個網址時,瀏覽器會使用 HTTP 協定向伺服器請求資料,然後伺服器會回傳資料給瀏覽器,這樣你就可以在瀏覽器上看到網頁內容。
那麼 HTTP 本身也是有版本之差,但這邊我們只需要知道 HTTP/1.1、HTTP/2 與 HTTP/3 這三個版本就可以了。
而 HTTP/2 與 HTTP/3 是 HTTP/1.1 的升級版本,主要是為了提高網路傳輸效率與安全性,但我們比較需要知道 HTTP/1.1 的特性,其中 RESTful API 就是基於 HTTP/1.1 協定來設計的,在 HTTP/1.1 中就定義了八種請求方法(Request Method),分別是:
這些請求方法用來告訴伺服器你想要做什麼操作,例如 GET 用來請求資料,POST 用來提交資料等。
其中 GET 與 HEAD 是被定義為 「安全的」 請求,,也就是說它們不會對伺服器資源造成任何修改或影響。換句話說,你可以放心用 GET 或 HEAD 來請求資料,而不必擔心會動到伺服器。
為什麼說這兩個請求方法是「安全的」呢?在網路世界裡有一個行為叫做「爬蟲」,它的原理就是透過 GET 請求 來抓取網頁資料。如果 GET 不是安全的,那就意味著爬蟲在取得資料的同時,也可能修改伺服器上的資源,這顯然會造成嚴重的安全問題。
相對的,POST、PUT、DELETE 則被定義為 「不安全的」 請求,因為它們可能會修改或影響伺服器上的資源,因此在使用這些方法時,就需要特別謹慎。
當然,實務上並不能百分之百保證 GET 請求一定安全,因為有些網站可能會用 GET 來修改伺服器上的資源。
在理解 HTTP 基本概念後,這裡還要補充一點:HTTP 的傳輸是 「明文傳輸」,也就是說資料在傳輸過程中並沒有加密,任何人只要攔截到封包,就能直接讀取內容。
Note
明文傳輸是指資料在傳輸過程中沒有經過任何加密處理,這意味著任何人都可以輕易地讀取到傳輸的內容。
為了證明 HTTP 是明文傳輸,接下來我會示範如何利用 Wireshark 抓取 HTTP 封包,並展示其中的內容是多麼容易被直接讀取出來。
Note
開始前,請到 Wireshark 官方網站 下載並安裝 Wireshark 工具。
由於接下來範例都會需要撰寫程式碼,若不方便撰寫的話也不用擔心,本文將會各步驟截圖介紹盡可能讓讀者閱讀時,可以不用準備環境,但如果可以跟著一起做,那麼學習體感上絕對是比較好唷!
首先,請先下載這份我準備好的 GitHub 專案 這個專案裡包含一個簡易的登入畫面,且只能使用以下帳號密碼登入:
admin
密碼:password123
user
密碼:secret456
test
密碼:test789
下載並取得這個專案後,請依照以下步驟操作:
npm install
安裝相關套件npm start
啟動專案http://localhost:3000
就能看到我準備好的範例登入畫面。接下來,請打開 Wireshark,並選擇要監控的網路介面(例如 Wi-Fi 或乙太網路)。在這個範例中,我們要監控的是本機的流量,所以請選擇 Loopback 介面(通常顯示為 lo
)。
這時候你會發現,在 Wireshark 畫面中會不斷出現大量訊息,這就是因為 Wireshark 正在即時監控並顯示網路流量。
接著,回到專案頁面,輸入帳號密碼登入。當你看到登入後的畫面時,就可以切回 Wireshark,準備查看剛剛產生的封包了。
這時候 Wireshark 畫面應該會像瘋狂跳動一樣持續刷新。為了避免干擾,你可以點一下上方的 「停止」 按鈕,讓 Wireshark 暫停監控網路流量。
由於封包資訊量非常龐大,我們需要過濾結果,請在上方的搜尋列輸入以下過濾條件: tcp.port == 3000 and http.request.method == "POST"
Note
這個搜尋條件意思是指「只顯示 TCP 端口為 3000 ,且請求方法為 POST 的 HTTP 封包」,就能過濾掉其他不相關的封包。
接著,你應該會看到一個 POST 請求 的封包。點擊它之後,在下方的 「封包內容」 區域就能看到詳細的請求資訊,包含你剛剛輸入的帳號與密碼!
這正是 HTTP 明文傳輸 的特性——任何人都能輕易讀取傳輸內容,而這也正是 HTTP 被認為 不安全 的主要原因。
Note
在本地開發時,通常會預設使用 HTTP 協定,因為此時並不需要特別考慮安全性問題。但在實際的 生產環境 中,則必須使用 HTTPS 協定,來確保資料傳輸的安全。
那如果是 HTTPS 呢?
簡單來說,HTTPS 就是 HTTP + SSL/TLS 加密協定,能確保資料在傳輸過程中是加密的。這代表即使有人截取了封包,也無法輕易讀取其中內容。
要啟用 SSL/TLS 加密,伺服器必須有一個 SSL 憑證(Certificate),而這個憑證需要由受信任的 憑證機構(CA) 簽發,才能確保連線安全。
在我提供的範例專案中,我準備了一段 Shell Script 指令,方便你快速產生 SSL 憑證:
#!/bin/bash
mkdir -p cert
openssl req -nodes -new -x509 -keyout cert/server.key -out cert/server.crt -days 365 -subj "/C=TW/ST=Taiwan/L=Taipei/O=Demo/OU=Dev/CN=localhost"
echo "自簽名憑證已產生於 cert/server.key 和 cert/server.crt"
簡單來說,這段指令會在範例專案底下建立一個 cert
資料夾,並在其中產生 server.key
與 server.crt
兩個檔案,就是我們需要用來啟用 HTTPS 的 SSL 憑證。
Note
OpenSSL 是一個開源的加密工具,可以用來生成 SSL 憑證與私鑰。不過要注意,正式環境 必須向受信任的憑證機構(CA)申請 SSL 憑證,自行產生的憑證僅適用於 開發與測試環境。
所以,你只需要執行這個指令,就能產生 SSL 憑證。接著,就可以在專案中使用這個憑證來啟動 HTTPS 伺服器了。
sh generate-cert.sh
npm start
接著請輸入: https://localhost:3443
,請特別注意這裡是 https
而不是 http
。
進入登入畫面後,你會發現 Chrome 瀏覽器跳出一個 警告訊息。這是因為我們使用的是 自簽名憑證,瀏覽器無法驗證其真實性,所以才會顯示警告。
接下來的流程和前面相同:輸入帳號密碼登入,然後回到 Wireshark 查看封包內容。
不過這裡要特別注意,篩選條件需要改成:
tcp.port == 3443
你會發現這裡少了 http.request.method == "POST"
,原因是 HTTPS 在傳輸過程中會加密,所以我們無法直接看到請求方法。
那要怎麼辨別呢?其實可以透過「封包大小」來推測,因為 POST 請求通常比 GET 大,在 Wireshark 中,可以查看「Length」欄位來判斷。
例如這裡顯示花費了 4.059109 秒,我們就能推測這就是剛剛輸入帳號密碼時的 POST 請求。
但不管怎麼看,你都無法看到帳號密碼的內容,因為 HTTPS 的加密機制 已經把資料保護起來了~
那...我們有辦法看到嗎?
其實還是有辦法解密的,畢竟是自己弄的簽證,不過這部分就不在今天的範圍內了。
畢竟這篇的重點,只是要讓你了解 HTTP 與 HTTPS 的差異而已~
從這一章開始,難度相較前面會大幅提升,因為會出現許多你可能不熟悉的名詞,例如 GitHub
、npm
、Node.js
、Express
、Wireshark
等等。
不過不用擔心,我會盡可能在每個步驟都附上 圖片 + 說明,即使沒有程式背景的人也能跟著完成。
當然,如果你本身有程式基礎,那我會建議你邊看邊實際操作,效果會更好、更有感!
本文將同步更新至以下網站: